﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Collections;

namespace Faml.Frontend
{
    /// <summary>Expression for constructing anonymous struct (or dictionary)</summary>
    public class FamlDictionaryExpression : FamlExpression
    {
        private OrderedDictionary fields;

        public FamlDictionaryExpression(OrderedDictionary fields)
        {
            this.fields = fields;
            MakeMetadata();
        }

        public string[] GetKeys()
        {
            string[] keys = new string[fields.Count];
            fields.Keys.CopyTo(keys, 0);
            return keys;
        }

        public bool ContainsField(string name)
        {
            return fields.Contains(name);
        }

        public FamlExpression GetField(string name)
        {
            return fields[name] as FamlExpression;
        }

        public override FamlExpression Expand()
        {
            OrderedDictionary expandedFields = new OrderedDictionary(fields.Count);
            foreach (DictionaryEntry field in fields)
                expandedFields.Add((string)field.Key, ((FamlExpression)field.Value).Expand());
            return new FamlDictionaryExpression(expandedFields);
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("{");
            bool first = true;
            foreach (DictionaryEntry field in fields)
            {
                if (!first)
                    sb.Append(",");
                else
                    first = false;
                sb.Append(field.Key);
                sb.Append("=");
                sb.Append(field.Value);
            }
            sb.Append("}");
            return sb.ToString();
        }

        protected override Type ComputeType()
        {
            return typeof(OrderedDictionary);
        }

        protected override void MakeMetadata()
        {
            metadata.Height = 0;
            metadata.Hash = NodeType.GetHashCode();
            foreach (DictionaryEntry field in fields)
            {
                FamlExpression exp = (FamlExpression)field.Value;
                metadata.Height = Math.Max(metadata.Height, exp.Metadata.Height + 1);
                metadata.Hash ^= field.Key.GetHashCode() ^ exp.Metadata.Hash;
                metadata.AddIfNotExist(exp.NodeParameters);
            }
        }

        public override FamlExpressionType NodeType
        {
            get { return FamlExpressionType.Dictionary; }
        }

        public override IEnumerable<FamlExpression> Children
        {
            get
            {
                for (int i = 0; i < fields.Count; i++)
                {
                    yield return fields[i] as FamlExpression;
                }
            }
        }
    }
}